package com.ccm.demo.springbootsecurity.configuration;

import com.ccm.demo.springbootsecurity.security.*;
import com.ccm.demo.springbootsecurity.service.CorsFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.header.HeaderWriter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	@Resource
	UserDetailsServiceImpl userDetailsService;
	@Resource
	UrlFilterInvocationSecurityMetadataSource urlFilterInvocationSecurityMetadataSource;
	@Resource
	UrlAccessDecisionManager urlAccessDecisionManager;
	@Resource
	AuthenticationAccessDeniedHandler authenticationAccessDeniedHandler;
	@Resource
	CorsFilter corsFilter;
	@Resource
	CorsConfigurationSourceImpl corsConfigurationSource;

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
	}

	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/static/**");
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
				.antMatchers(HttpMethod.OPTIONS).permitAll()
			.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
				@Override
				public <O extends FilterSecurityInterceptor> O postProcess(O o) {
					o.setSecurityMetadataSource(urlFilterInvocationSecurityMetadataSource);
					o.setAccessDecisionManager(urlAccessDecisionManager);
					return o;
				}
			})
			.and().cors().configurationSource(corsConfigurationSource)
			.and()
			.formLogin().loginPage("/login.html").loginProcessingUrl("/login").usernameParameter("username").passwordParameter("password").permitAll()
			.failureHandler((httpServletRequest, httpServletResponse, e) -> {
				httpServletResponse.setContentType("application/json;charset=utf-8");
				PrintWriter out = httpServletResponse.getWriter();
				StringBuffer sb = new StringBuffer();
				sb.append("{\"code\":\"400\",\"msg\":\"");
				if (e instanceof UsernameNotFoundException || e instanceof BadCredentialsException) {
					sb.append("用户名或密码错误!");
				} else if (e instanceof DisabledException) {
					sb.append("账户被禁用!");
				} else {
					sb.append("登录失败!");
				}
				sb.append("\"}");
				out.write(sb.toString());
				out.flush();
				out.close();
			})
			.successHandler((httpServletRequest, httpServletResponse, authentication) -> {
				httpServletResponse.setContentType("application/json;charset=utf-8");
				PrintWriter out = httpServletResponse.getWriter();
				ObjectMapper objectMapper = new ObjectMapper();
				String s = "{\"code\":\"0\",\"data\":" + objectMapper.writeValueAsString(getCurrentUser()) + "}";
				out.write(s);
				out.flush();
				out.close();
			})
			.and().logout().permitAll()
			.and().csrf().disable().exceptionHandling().accessDeniedHandler(authenticationAccessDeniedHandler)
														.authenticationEntryPoint(new UnLoginHandler("https://www.bestyxsj.com/50x.html"));
	}

	private User getCurrentUser() {
		return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
	}
}
